package com.newsnetwork.files.controller;

import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSFindIterable;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.model.Filters;
import com.newsnetwork.api.controller.files.FileUploaderControllerApi;
import com.newsnetwork.exception.GraceException;
import com.newsnetwork.files.resource.FileResource;
import com.newsnetwork.files.service.UploaderService;
import com.newsnetwork.grace.result.CommonJSONResult;
import com.newsnetwork.grace.result.ResponseStatusEnum;
import com.newsnetwork.pojo.bo.NewAdminBO;
import com.newsnetwork.utils.FileUtils;
import com.newsnetwork.utils.extend.AliImageReviewUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author DingNing, HuangDekai
 * @date 2022/11/9 13:25
 * @Description:
 */
@RestController
public class FileUploaderController implements FileUploaderControllerApi {
    final static Logger logger = LoggerFactory.getLogger(FileUploaderController.class);

    @Autowired
    private UploaderService uploaderService;

    @Autowired
    private FileResource fileResource;
    @Autowired
    private AliImageReviewUtils aliImageReviewUtils;

    @Autowired
    private GridFSBucket gridFSBucket;

    /**
     * 上传用户头像-单文件上传
     * @param userId 用户ID
     * @param file   文件对象
     * @return
     * @throws Exception
     */
    @Override
    public CommonJSONResult uploadFace(String userId, MultipartFile file) throws Exception {
        String path = "";
        // 1.1判断ID不能为空
        if (!StringUtils.isNotBlank(userId))
            return CommonJSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
        // 1.2判断文件不能为空
        if (file != null) {
            // 2.1获得文件上传的名称
            String fileName = file.getOriginalFilename();

            // 2.2判断文件名不能为空
            if (StringUtils.isNotBlank(fileName)) {
                // 2.3获得文件后缀名
                String fileNameArr[] = fileName.split("\\.");
                String suffix = fileNameArr[fileNameArr.length - 1];
                // 2.4判断后缀符合我们的预定义规范
                if (!suffix.equalsIgnoreCase("png") &&
                        !suffix.equalsIgnoreCase("jpg") &&
                        !suffix.equalsIgnoreCase("jpeg")
                ) {
                    return CommonJSONResult.errorCustom(ResponseStatusEnum.FILE_FORMATTER_FAILD);
                }

                // 3执行上传
//                path = uploaderService.uploadFdfs(file, suffix);
                path = uploaderService.uploadOSS(file, userId, suffix);

            } else {
                return CommonJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_NULL_ERROR);
            }
        } else {
            return CommonJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_NULL_ERROR);
        }

        logger.info("path = " + path);

        String finalPath = "";
        if (StringUtils.isNotBlank(path)) {
//            finalPath = fileResource.getHost() + path;
            finalPath = fileResource.getOssHost() + path;
        } else {
            return CommonJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_FAILD);
        }

//        return CommonJSONResult.ok(doAliImageReview(finalPath));
        return CommonJSONResult.ok(finalPath);
    }

    /**
     * 多文件上传
     * @param userId
     * @param files
     * @return
     * @throws Exception
     */
    @Override
    public CommonJSONResult uploadSomeFiles(String userId, MultipartFile[] files) throws Exception {
        // 声明list，用于存放多个图片的地址路径，返回到前端
        List<String> imageUrlList = new ArrayList<>();
        if (files != null && files.length > 0) {
            for (MultipartFile file : files) {
                String path = "";
                if (file != null) {
                    // 获得文件上传的名称
                    String fileName = file.getOriginalFilename();

                    // 判断文件名不能为空
                    if (StringUtils.isNotBlank(fileName)) {
                        String fileNameArr[] = fileName.split("\\.");
                        // 获得后缀
                        String suffix = fileNameArr[fileNameArr.length - 1];
                        // 判断后缀符合我们的预定义规范
                        if (!suffix.equalsIgnoreCase("png") &&
                                !suffix.equalsIgnoreCase("jpg") &&
                                !suffix.equalsIgnoreCase("jpeg")
                        ) {
                            continue;
                        }

                        // 执行上传
//                        path = uploaderService.uploadFdfs(file, suffix);
                        path = uploaderService.uploadOSS(file, userId, suffix);

                    } else {
                        continue;
                    }
                } else {
                    continue;
                }

                String finalPath = "";
                if (StringUtils.isNotBlank(path)) {
//                    finalPath = fileResource.getHost() + path;
                    finalPath = fileResource.getOssHost() + path;
//                    finalPath = doAliImageReview(finalPath);
                    imageUrlList.add(finalPath);
                } else {
                    continue;
                }
            }
        }

        return CommonJSONResult.ok(imageUrlList);
    }

    public static final String FAILED_IMAGE_URL = "https://newsnetwork.oss-cn-hangzhou.aliyuncs.com/images/failed.jpeg";
    /**
     *  图片检测
     * @param finalPath 图片地址
     * @return
     */
    private String doAliImageReview(String finalPath) {
        boolean result = false;
        try {
            result = aliImageReviewUtils.reviewImage(finalPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (!result) {
            return finalPath;
        }
        return FAILED_IMAGE_URL;
    }

    /**
     * 文件上传到 mongodb 的 gridFS 中, 无法使用 swagger 调用
     *
     * @param newAdminBO adminBO 对象体
     */
    @Override
    public CommonJSONResult uploadToGridFS(NewAdminBO newAdminBO) throws Exception {
        // 获得图片的 base64 字符串
        String file64 = newAdminBO.getImg64();
        // 将 base64 字符串转换为 byte 数组
        byte[] bytes = new BASE64Decoder().decodeBuffer(file64.trim());
        // 转换为输入流
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        // 上传到 gridFS 中
        ObjectId fileId = gridFSBucket.uploadFromStream(newAdminBO.getAdminName() + ".png", byteArrayInputStream);
        // 获得文件在 gridFS 中的主键 id
        String fileIdStr = fileId.toString();
        return CommonJSONResult.ok(fileIdStr);
    }

    /**
     * 从 gridFS 中读取图片内容
     *
     * @param faceId 图片id
     */
    @Override
    public void readInGridFS(String faceId, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 判空
        if (StringUtils.isBlank(faceId) || faceId.equalsIgnoreCase("null")) {
            GraceException.display(ResponseStatusEnum.FILE_NOT_EXIST_ERROR);
        }
        // 从 gridFS 中下载图片到程序运行所在的计算机中, 获取下载好的图片的文件流
        File adminFace = readGridFSByNameFaceId(faceId);

        // 把人脸图片以文件流形式输出到浏览器
        FileUtils.downloadFileByStream(response, adminFace);
    }

    /**
     * 根据 faceId 在 GridFS 查询图片
     *          该方法会将 faceId 对应的图片从 MongoDB 的 GridFS 下载到程序运行的计算机的 ../tmp/img 目录,
     *          然后返回那个文件的文件流
     * @param faceId faceId
     * @return 对应图片文件的文件流
     */
    private File readGridFSByNameFaceId(String faceId) throws Exception {
        // 根据 id 查询, 得到的是可遍历的对象(类似列表)
        GridFSFindIterable gridFSFiles = gridFSBucket.find(Filters.eq("_id", new ObjectId(faceId)));
        // 获取列表中的第一个文件, 也可能是 null
        GridFSFile gridFSFile = gridFSFiles.first();
        // 文件不存在, 抛出异常
        if (gridFSFile == null) {
            GraceException.display(ResponseStatusEnum.FILE_NOT_EXIST_ERROR);
        }
        // 存在
        String filename = gridFSFile.getFilename();
        logger.info("查看文件: {}", filename);
        // 获取文件流, 保存文件到本地, 或者保存到服务器临时目录
        File tmpFile = new File("../tmp/img");
        if (!tmpFile.exists()) {
            tmpFile.mkdirs();
        }
        File myFile = new File("../tmp/img/" + filename);
        // 创建文件输出流
        FileOutputStream os = new FileOutputStream(myFile);
        // 下载到服务器或本地
        gridFSBucket.downloadToStream(new ObjectId(faceId), os);

        return myFile;
    }
}
